package org.lboot.flow.processor.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.lboot.flow.constant.FlowNodeTypeConst;
import org.lboot.flow.constant.FlowWorkStatusConst;
import org.lboot.flow.constant.FlowWorkStatusEnum;
import org.lboot.flow.model.FlowModel;
import org.lboot.flow.model.node.BaseModel;
import org.lboot.flow.model.node.DecisionTaskModel;
import org.lboot.flow.module.audit.FlowAudit;
import org.lboot.flow.module.audit.FlowAuditService;
import org.lboot.flow.module.work.FlowWork;
import org.lboot.flow.module.work.FlowWorkService;
import org.lboot.flow.module.work.params.FlowTaskParams;
import org.lboot.flow.parser.FlowNodeParser;
import org.lboot.flow.processor.FlowNodeProcessor;
import org.lboot.flow.event.system.FlowBlockEvent;
import org.lboot.flow.event.system.FlowProcessEvent;
import org.lboot.flow.event.system.FlowUnBlockEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Service
@AllArgsConstructor
public class DecisionTaskNodeProcessorImpl implements FlowNodeProcessor {

    // 流程实例服务
    FlowWorkService flowWorkService;

    FlowAuditService flowAuditService;

    @Resource
    ApplicationContext context;

    @Override
    public String getNodeType() {
        return FlowNodeTypeConst.DECISION_TASK_NODE;
    }

    @Override
    @SneakyThrows
    @Transactional
    public void process(FlowWork flowWork, FlowTaskParams taskParams) {
        FlowWork oldFlow = new FlowWork();
        BeanUtil.copyProperties(flowWork,oldFlow, CopyOptions.create().setIgnoreError(true).setIgnoreNullValue(true));
        // 流程执行到下一步
        BaseModel currentNode = flowWork.getCurrentModel();
        // 获取节点类型
        DecisionTaskModel taskModel = (DecisionTaskModel) currentNode;
        // 获取可选决策列表
        List<String> nodeIds = taskModel.getNodeIds();
        // 获取审计信息
        FlowAudit audit = new FlowAudit();
        audit.setFlowNodeId(taskModel.getId());
        audit.setFlowNodeName(taskModel.getName());
        audit.setFlowWorkId(flowWork.getId());
        Example<FlowAudit> example = Example.of(audit);
        List<FlowAudit> audits = flowAuditService.getExample(example);
        // 如果存在审计记录
        String decisionResult = null;
        for (FlowAudit item:audits){
            // 符合内容的设计
            if (nodeIds.contains(item.getAuditResult())){
                decisionResult = item.getAuditResult();
            }
        }

        // 存在符合条件的审计结果
        if (Validator.isNotEmpty(decisionResult)){
            BaseModel nextModel = flowWork.getNodeModel(decisionResult);
            flowWork.setCurrentNodeId(nextModel.getId());
            flowWork.setCurrentNodeType(nextModel.getNodeType());
            flowWork.setNextNodeId(nextModel.getNextNodeId());
            // 恢复进行态度
            flowWork.setFlowWorkStatus(FlowWorkStatusEnum.IN_PROCESS.value);
            flowWorkService.updateOne(flowWork);
            // 发布流程阻塞解除事件
            context.publishEvent(new FlowUnBlockEvent(this,flowWork));
            // 发布流程流转事件
            context.publishEvent(new FlowProcessEvent(this,oldFlow,flowWork));
        }else {
            // 阻塞
            flowWork.setFlowWorkStatus(FlowWorkStatusEnum.BLOCKED.value);
            taskParams.setRemark("无审计信息");
            flowWorkService.updateOne(flowWork);
            // 流程阻塞事件
            context.publishEvent(new FlowBlockEvent(this,flowWork));
        }
    }

    @Override
    public void back(FlowWork flowWork, FlowTaskParams taskParams) {

    }
}
